package com.liuyi.netty.im.server.handle.storage.impl;

import cn.hutool.core.util.StrUtil;
import com.liuyi.netty.im.commons.enums.UserLineStatus;
import com.liuyi.netty.im.server.handle.storage.User;
import com.liuyi.netty.im.server.handle.storage.UserStorage;
import com.liuyi.netty.im.server.util.ImHelp;
import io.netty.channel.Channel;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Mr.Fmy
 * @since 2021/12/23
 */
public class DefaultUserStorage implements UserStorage {

    private final Map<String, Set<String>> MAP = new ConcurrentHashMap<>();
    private final Map<String, User> MAP_USER = new ConcurrentHashMap<>();

    private String key(String userId, String device) {
        return userId + "@" + device;
    }

    @Override
    public User getUser(String userId, String device) {
        return MAP_USER.get(key(userId, device));
    }

    @Override
    public List<User> listUser(String userId) {
        List<User> users = new ArrayList<>();
        if (MAP.containsKey(userId)){
            Set<String> userIds = MAP.get(userId);
            if (userIds != null) {
                userIds.forEach(id -> users.add(MAP_USER.get(id)));
            }
        }
        return users;
    }

    @Override
    public User onLine(Channel channel, String sign, String userId, String device) {
        if (StrUtil.isEmpty(sign) || StrUtil.isEmpty(userId) || StrUtil.isEmpty(device)) {
            return null;
        }
        Set<String> userIds = MAP.get(userId);
        if (userIds == null) {
            synchronized (MAP) {
                userIds = MAP.computeIfAbsent(userId, k -> Collections.synchronizedSet(new HashSet<>()));
            }
        }
        String key = key(userId, device);
        userIds.add(key);
        User user = getUser(userId, device);
        if (user == null) {
            user = new User();
        }
        user.setIp(ImHelp.getChannelIp(channel)).setUserId(userId).setDevice(device)
                .setLastLoginTime(System.currentTimeMillis())
                .setChannelId(channel.id().asLongText())
                .setUserLineStatus(UserLineStatus.ON);
        MAP_USER.put(key, user);
        return user;
    }

    @Override
    public User offLine(String userId, String device) {
        if (StrUtil.isEmpty(userId) || StrUtil.isEmpty(device)) {
            return null;
        }
        User user = getUser(userId, device);
        if (user != null) {
            user.offline();
        }
        return user;
    }
}
